﻿using Ekton_Manage_DomainCore.Aggregate;
using Ekton_Manage_Framework.Methods;
using Ekton_Manage_Mapper.EntityMappers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Ekton_Manage_Web.Filter
{
    /// <summary>
    /// 全局异常及日志处理
    /// </summary>
    public class GlobalExceptionFilter : IExceptionFilter
    {
        private readonly SystemLogMapper _systemLog;
        private readonly ILogger<GlobalExceptionFilter> _logger;
        private readonly IWebHostEnvironment _env;
        private readonly HttpGetUser _httpGetUser;
        public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger,
            IWebHostEnvironment env,
            SystemLogMapper systemLog,
            HttpGetUser httpGetUser)
        {
            _logger = logger;
            _env = env;
            _systemLog = systemLog;
            _httpGetUser = httpGetUser;
        }

        /// <summary>
        /// 发生异常时进入
        /// </summary>
        /// <param name="context"></param>
        public void OnException(ExceptionContext context)
        {
            try
            {
                var json = new JsonErrorResponse();

                json.Message = context.Exception.Message;//错误信息
                if (_env.IsDevelopment())
                {
                    json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息
                }
                //context.Result = new InternalServerErrorObjectResult(json);
                MiniProfiler.Current.CustomTiming("Errors：", json.Message);
                //采用Serilog 进行错误日志记录
                //_logger.LogError(json.Message + WriteLog(json.Message, context.Exception));
                if (!context.ExceptionHandled)
                {
                    context.Result = new ContentResult
                    {
                        //在异步方法中可使用await,不然则Result()
                        Content = JsonConvert.SerializeObject(new
                        {
                            msg = "服务器异常",
                            success = false,
                            code = 500,
                            exception = context.Exception.Message
                        }),
                        /*Content = context.Exception.Message,*///这里是把异常抛出。也可以不抛出。
                        StatusCode = StatusCodes.Status200OK,
                        ContentType = "text/html;charset=utf-8"
                    };
                }
                context.ExceptionHandled = true;
            }
            finally
            {
                var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
                _systemLog.InsertSingleData(new system_log { ip_address = _httpGetUser.GetClientIP().Result, oper_type = $"{context.HttpContext.Request.Method}", oper_describe = $"ActionUrl:{controllerActionDescriptor.ControllerTypeInfo.FullName}.{controllerActionDescriptor.ActionName}", level = "Error", exception = context.Exception.Message });
            }

        }

        /// <summary>
        /// 自定义返回格式
        /// </summary>
        /// <param name="throwMsg"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public string WriteLog(string throwMsg, Exception ex)
        {
            return string.Format("\r\n【自定义错误】：{0} \r\n【异常类型】：{1} \r\n【异常信息】：{2} \r\n【堆栈调用】：{3}", new object[] { throwMsg,
                ex.GetType().Name, ex.Message, ex.StackTrace });
        }

        /// <summary>
        /// 异步发生异常时进入
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public Task OnExceptionAsync(ExceptionContext context)
        {
            OnException(context);
            return Task.CompletedTask;
        }

        public class InternalServerErrorObjectResult : ObjectResult
        {
            public InternalServerErrorObjectResult(object value) : base(value)
            {
                StatusCode = StatusCodes.Status500InternalServerError;
            }
        }

        //返回错误信息
        public class JsonErrorResponse
        {
            /// <summary>
            /// 生产环境的消息
            /// </summary>
            public string Message { get; set; }
            /// <summary>
            /// 开发环境的消息
            /// </summary>
            public string DevelopmentMessage { get; set; }
        }
    }
}
